# Options

option(BUILD_SHARED_LIBS "Build shared libs" ON)
option(BUILD_STATIC_TEST_BINS "Build statically linked test executables" OFF)
option(ENABLE_LTO "Enable LTO on GCC or ThinLTO on clang" OFF)
option(BUILD_LIBM "libsleef will be built." ON)
option(BUILD_DFT "libsleefdft will be built." ON)
option(BUILD_QUAD "libsleefquad will be built." OFF)
option(BUILD_GNUABI_LIBS "libsleefgnuabi will be built." ON)
option(BUILD_TESTS "Tests will be built." ON)
option(BUILD_INLINE_HEADERS "Build header for inlining whole SLEEF functions" OFF)

option(SLEEF_TEST_ALL_IUT "Perform tests on implementations with all vector extensions" OFF)
option(SLEEF_SHOW_CONFIG "Show SLEEF configuration status messages." ON)
option(SLEEF_SHOW_ERROR_LOG "Show cmake error log." OFF)

option(ENFORCE_TESTER "Build fails if tester is not available" OFF)
option(ENFORCE_TESTER3 "Build fails if tester3 is not built" OFF)

option(ENABLE_ALTDIV  "Enable alternative division method (aarch64 only)" OFF)
option(ENABLE_ALTSQRT "Enable alternative sqrt method (aarch64 only)" OFF)

option(DISABLE_FFTW "Disable testing the DFT library with FFTW" OFF)

option(ENABLE_CUDA "Enable CUDA" OFF)

cmake_minimum_required(VERSION 3.4.3)

# Set to NEW when updating cmake_minimum_required to VERSION >= 3.7.2
if(${CMAKE_VERSION} VERSION_GREATER "3.7.1")
  cmake_policy(SET CMP0066 OLD)
endif()

if(${CMAKE_VERSION} VERSION_GREATER "3.14.99")
  cmake_policy(SET CMP0091 NEW)
endif()

enable_testing()

set(SLEEF_VERSION_MAJOR 3)
set(SLEEF_VERSION_MINOR 6)
set(SLEEF_VERSION_PATCHLEVEL 0)
set(SLEEF_VERSION ${SLEEF_VERSION_MAJOR}.${SLEEF_VERSION_MINOR}.${SLEEF_VERSION_PATCHLEVEL})
set(SLEEF_SOVERSION ${SLEEF_VERSION_MAJOR})

if (ENABLE_CUDA)
  project(SLEEF
    VERSION ${SLEEF_VERSION}
    LANGUAGES C CUDA)
else()
  project(SLEEF
    VERSION ${SLEEF_VERSION}
    LANGUAGES C)
endif()

# For specifying installation directories
include(GNUInstallDirs)

if(NOT DEFINED sleef_SOURCE_DIR)
   set(sleef_SOURCE_DIR ${CMAKE_SOURCE_DIR})
endif()

if(NOT DEFINED sleef_BINARY_DIR)
   set(sleef_BINARY_DIR ${CMAKE_BINARY_DIR})
endif()

# Sanity check for in-source builds which we do not want to happen
if(sleef_SOURCE_DIR STREQUAL sleef_BINARY_DIR)
  message(FATAL_ERROR "SLEEF does not allow in-source builds.
You can refer to doc/build-with-cmake.md for instructions on how provide a \
separate build directory. Note: Please remove autogenerated file \
`CMakeCache.txt` and directory `CMakeFiles` in the current directory.")
endif()

if(ENABLE_LTO AND BUILD_SHARED_LIBS)
  message(FATAL_ERROR "ENABLE_LTO and BUILD_SHARED_LIBS cannot be specified at the same time")
endif(ENABLE_LTO AND BUILD_SHARED_LIBS)

if(ENABLE_LTO)
  cmake_policy(SET CMP0069 NEW)
  include(CheckIPOSupported)
  check_ipo_supported(RESULT supported OUTPUT error)
endif()

# Set output directories for the library files
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)

foreach(CONFIG ${CMAKE_CONFIGURATION_TYPES})
  string(TOUPPER ${CONFIG} CONFIG)
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG} ${PROJECT_BINARY_DIR}/lib)
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG} ${PROJECT_BINARY_DIR}/lib)
  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG} ${PROJECT_BINARY_DIR}/bin)
endforeach(CONFIG CMAKE_CONFIGURATION_TYPES)

# Path for finding cmake modules
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
set(SLEEF_SCRIPT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Scripts CACHE PATH
  "Path for finding sleef specific cmake scripts")

if (CMAKE_C_COMPILER_ID MATCHES "Clang" AND "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
  message(STATUS "Building with Clang on Windows")
  set(SLEEF_CLANG_ON_WINDOWS TRUE)
endif()

# sleef-config.h.in passes cmake settings to the source code
include(Configure.cmake)
configure_file(
  ${PROJECT_SOURCE_DIR}/sleef-config.h.in
  ${PROJECT_BINARY_DIR}/include/sleef-config.h @ONLY)

# We like to have a documented index of all targets in the project. The
# variables listed below carry the names of the targets defined throughout
# the project.

# Generates object file (shared library) `libsleef`
# Defined in src/libm/CMakeLists.txt via command add_library
set(TARGET_LIBSLEEF "sleef")
set(TARGET_LIBSLEEFGNUABI "sleefgnuabi")
# Generates the sleef.h headers and all the rename headers
# Defined in src/libm/CMakeLists.txt via custom commands and a custom target
set(TARGET_HEADERS "headers")
set(TARGET_INLINE_HEADERS "inline_headers")
set(TARGET_LIBINLINE "sleefinline")
# Generates executable files for running the test suite
# Defined in src/libm-tester/CMakeLists.txt via command add_executable
set(TARGET_TESTER "tester")
set(TARGET_IUT "iut")
# The target to generate LLVM bitcode only, available when SLEEF_ENABLE_LLVM_BITCODE is passed to cmake
set(TARGET_LLVM_BITCODE "llvm-bitcode")
# Generates the helper executable file mkrename needed to write the sleef header
set(TARGET_MKRENAME "mkrename")
set(TARGET_MKRENAME_GNUABI "mkrename_gnuabi")
set(TARGET_MKMASKED_GNUABI "mkmasked_gnuabi")
# Generates the helper executable file mkdisp needed to write the sleef header
set(TARGET_MKDISP "mkdisp")
set(TARGET_MKALIAS "mkalias")
# Generates static library common
# Defined in src/common/CMakeLists.txt via command add_library
set(TARGET_LIBCOMMON_OBJ "common")
set(TARGET_LIBARRAYMAP_OBJ "arraymap")

# Function used to add an executable that is executed on host
function(add_host_executable TARGETNAME)
  if (NOT CMAKE_CROSSCOMPILING)
    add_executable(${TARGETNAME} ${ARGN})
  else()
    add_executable(${TARGETNAME} IMPORTED)
    set_property(TARGET ${TARGETNAME} PROPERTY IMPORTED_LOCATION ${NATIVE_BUILD_DIR}/bin/${TARGETNAME})
  endif()
endfunction()

function(host_target_AAVPCS_definitions TARGETNAME)
  if (NOT CMAKE_CROSSCOMPILING)
    target_compile_definitions(${TARGETNAME} PRIVATE ENABLE_AAVPCS=1)
  endif()
endfunction()

# Generates object file (shared library) `libsleefdft`
# Defined in src/dft/CMakeLists.txt via command add_library
set(TARGET_LIBDFT "sleefdft")

# Check subdirectories
add_subdirectory("src")

# Extra messages at configuration time. By default is active, it can be
# turned off by invoking cmake with "-DSLEEF_SHOW_CONFIG=OFF".
if(SLEEF_SHOW_CONFIG)
  message(STATUS "Configuring build for ${PROJECT_NAME}-v${SLEEF_VERSION}")
  message("   Target system: ${CMAKE_SYSTEM}")
  message("   Target processor: ${CMAKE_SYSTEM_PROCESSOR}")
  message("   Host system: ${CMAKE_HOST_SYSTEM}")
  message("   Host processor: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
  message("   Detected C compiler: ${CMAKE_C_COMPILER_ID} @ ${CMAKE_C_COMPILER}")
  message("   CMake: ${CMAKE_VERSION}")
  message("   Make program: ${CMAKE_MAKE_PROGRAM}")
  if(CMAKE_CROSSCOMPILING)
    message("   Crosscompiling SLEEF.")
    message("   Native build dir: ${NATIVE_BUILD_DIR}")
  endif(CMAKE_CROSSCOMPILING)
  message(STATUS "Using option `${SLEEF_C_FLAGS}` to compile libsleef")
  message(STATUS "Building shared libs : " ${BUILD_SHARED_LIBS})
  message(STATUS "Building static test bins: " ${BUILD_STATIC_TEST_BINS})
  message(STATUS "MPFR : " ${LIB_MPFR})
  if (MPFR_INCLUDE_DIR)
    message(STATUS "MPFR header file in " ${MPFR_INCLUDE_DIR})
  endif()
  message(STATUS "GMP : " ${LIBGMP})
  message(STATUS "RT : " ${LIBRT})
  message(STATUS "FFTW3 : " ${LIBFFTW3})
  message(STATUS "OPENSSL : " ${OPENSSL_VERSION})
  message(STATUS "SDE : " ${SDE_COMMAND})
  if (BUILD_INLINE_HEADERS)
    message(STATUS "SED : " ${SED_COMMAND})
  endif()
  message(STATUS "RUNNING_ON_TRAVIS : " ${RUNNING_ON_TRAVIS})
  message(STATUS "COMPILER_SUPPORTS_OPENMP : " ${COMPILER_SUPPORTS_OPENMP})
  if(ENABLE_GNUABI)
    message(STATUS "A version of SLEEF compatible  with libm and libmvec in GNU libc will be produced (${TARGET_LIBSLEEFGNUABI}.so)")
  endif()
  if (COMPILER_SUPPORTS_SVE)
    message(STATUS "Building SLEEF with VLA SVE support")
    if (ARMIE_COMMAND)
      message(STATUS "Arm Instruction Emulator found at ${ARMIE_COMMAND}")
      message(STATUS "SVE testing is done with ${SVE_VECTOR_BITS}-bits vectors.")
    endif()
  endif()
  if(FORCE_AAVPCS)
    message(STATUS "Building SLEEF with AArch64 Vector PCS support")
  endif()
endif(SLEEF_SHOW_CONFIG)

if (NOT CMAKE_MAKE_PROGRAM MATCHES "ninja")
  message("")
  message("*** Note: Parallel build is only supported with Ninja ***")
  message("")
endif()
